package lj.netty.websocket;

import cn.hutool.core.map.BiMap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelId;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

/**
 * Socket 工具类
 */
public class SocketUtils {
    /**
     * 所有通道容器
     */
    public static ChannelGroup GlobalGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    /**
     * 用户uuid 和 channelId 映射
     */
    public static BiMap<String, ChannelId> channels = new BiMap<>(new HashMap<>());

    /**
     * 获取 Mychannel
     */
    public static Channel getChannel(String target) {
        ChannelId channelId = channels.get(target);
        return null == channelId ? null : GlobalGroup.find(channelId);
    }

    /**
     * 添加channel到容器
     */
    public static void addChannel(Channel channel) {
        GlobalGroup.add(channel);
    }

    /**
     * 绑定用户和channel
     */
    public static void bindChannel(String target, ChannelId channelId) {
        if (channels.containsKey(target)) {
            ChannelId existChannelId = channels.get(target);
            if (null != existChannelId) {
                Channel existChannel = GlobalGroup.find(existChannelId);
                if (null != existChannel) {
                    GlobalGroup.remove(existChannel);
                }
            }
        }
        channels.put(target, channelId);
    }


    /**
     * 删除 Channel
     */
    public static void removeChannel(Channel channel) {
        channel.pipeline().remove(IdleStateHandler.class);
        channel.pipeline().remove(WebSocketHandler.class);
        channel.pipeline().remove(WebSocketServerProtocolHandler.class);
        GlobalGroup.remove(channel);

        if (channels.containsValue(channel.id())) {
            channels.getInverse().remove(channel.id());
        }
    }

    /**
     * 检查是否在线
     *
     * @param target
     * @return
     */
    public static boolean checkOnline(String target) {
        Channel channel = getChannel(target);
        if (channel == null || !channel.isOpen() || !channel.isActive()) {
            return false;
        } else {
            return true;
        }
    }


    /**
     * 检查是否在线 （多个）
     *
     * @param targets
     * @return
     */
    public static HashMap<String, Boolean> checkOnlines(List<String> targets) {
        HashMap<String, Boolean> map = new HashMap<>();
        for (String s : targets) {
            boolean online = checkOnline(s);
            map.put(s, online);
        }
        return map;
    }


    /**
     * 推送消息
     *
     * @param target
     * @param data
     * @return
     */
    public static boolean push(String target, String data) {
        Channel channel = getChannel(target);
        if (channel == null || !channel.isOpen() || !channel.isActive()) {
            return false;
        } else {
            channel.writeAndFlush(new TextWebSocketFrame(data));
            return true;
        }
    }

    /**
     * 推送多个目标消息
     *
     * @param targets
     * @param data
     * @return
     */
    public static List<String> pushMultiple(List<String> targets, String data) {
        ArrayList<String> success = new ArrayList<>();
        TextWebSocketFrame socketFrame = new TextWebSocketFrame(data);
        for (String target : targets) {
            Channel channel = getChannel(target);
            if (channel != null && channel.isOpen() && channel.isActive()) {
                channel.writeAndFlush(socketFrame);
                success.add(target);
            }
        }
        return success;
    }

    /**
     * 推送所有人消息
     *
     * @param data
     * @return
     */
    public static void pushAll(String data) {
        TextWebSocketFrame socketFrame = new TextWebSocketFrame(data);
        channels.forEach((k, v) -> {
            Channel channel = GlobalGroup.find(v);
            if (channel != null && channel.isOpen() && channel.isActive()) {
                channel.writeAndFlush(socketFrame);
            }
        });
    }

    /**
     * 删除连接
     *
     * @param target
     */
    public static void delTarget(String target) {
        Channel channel = getChannel(target);
        if (channel != null) {
            removeChannel(channel);
        }
    }

    public static List<String> getTargets() {
        List<String> targets = new ArrayList<>();
        Set<String> strings = channels.keySet();
        strings.forEach(e -> {
            String[] split = e.split("-");
            if (split.length <= 2) {
                targets.add(e);
            }
        });
        return targets;
    }

}
